#ifndef TC_STOCHASTIC_HPP
#define TC_STOCHASTIC_HPP

/** \file Stochastic.hpp
 * Definition of the Stochastic function template.
 *
 * (C) Copyright 2003-2006 by Semih Cemiloglu
 * All rights reserved, see COPYRIGHT file for details.
 *
 * $Id: Stochastic.hpp 110 2006-06-19 03:38:33Z semihc $
 *
 *
 */

#include "TA.hh"
#include "DBC.hpp"
#include "CircArray.hpp"



namespace TC {

  //! Stochastic oscillation calculator
  TC_EXPORT template <typename InputIterator,
                      typename OutputIterator,
                      class Adaptor>
  void Stochastic(InputIterator fromPos,
                  InputIterator fromEnd,
                  OutputIterator kPos,
                  OutputIterator dPos,
                  const unsigned kPeriod,
                  const unsigned kSlowingPeriod,
                  const unsigned dPeriod,
                  const Adaptor adaptor)
  {
    TC_PRE_CONDITION(kPeriod > 0);
    TC_PRE_CONDITION(dPeriod > 0);
    TC_PRE_CONDITION(kSlowingPeriod > 0);

    // Types
    typedef typename Adaptor::Price_t Price_t;
    typedef typename Adaptor::Volume_t Volume_t;

    register TAfp_t kval = 0.0;
    register TAfp_t dval = 0.0;
    Price_t cls, llow, hhigh;
    CircArray<Price_t> hi_arr(kPeriod);
    CircArray<Price_t> lo_arr(kPeriod);
    CircArray<TAfp_t> k_arr(kSlowingPeriod);
    CircArray<TAfp_t> d_arr(dPeriod);
    unsigned p = 0;

  
    for(; fromPos!=fromEnd; ++fromPos) {
      // Store low and high values
      lo_arr.push(adaptor.lo(*fromPos));
      hi_arr.push(adaptor.hi(*fromPos));
      
      if(++p < kPeriod) {
        *kPos++ = 0.0;
        *dPos++ = 0.0;
        continue;
      }


      // Find the lowest low
      llow = lo_arr.min();
      // Find the highest high
      hhigh = hi_arr.max();
      // Today's close
      cls = adaptor.cls(*fromPos);
      // Calculate %K
      // Check for division by zero
      if(hhigh!=llow)
        kval = ((cls-llow)/(hhigh-llow))*100;
      else
        kval = 0.0; // Would have been division by zero
      // Store the today's %K value
      k_arr.push(kval);
      // Get the slowed or average %K value
      kval = k_arr.avg();
      // Store it as new %K value
      d_arr.push(kval);
      // Get the %D value
      dval = d_arr.avg();
        
      // Store the %K and %D values
      *kPos++ = kval;
      *dPos++ = dval;

    } // end for

  }




} // end namespace


#endif /* Include guard */
